/******************************************************************************
** 公司名称：天津柯迪斯科技有限公司
** 版权信息：
** 文件名称： App_Protocol_LISHUI_CAN.c
** 模块名称： 溧水CAN协议处理模块
** 版 本 号： V1.0
** 作    者： 蒲磊
**
** 修改记录： 版本     修改人      时间         修改内容
******************************************************************************/

/******************************************************************************
* 头文件
******************************************************************************/
#include <string.h>
#include "Config.h"
#include "App_Protocol.h"
#include "App_MainTask.h"
#include "App_Parameter.h"
#include "multi_cyc_fifo.h"
#include "bsp.h"
/******************************************************************************
* 本文件宏定义 ('#define')
******************************************************************************/

/******************************************************************************
* 本文件类型定义 ('typedef')
******************************************************************************/

/******************************************************************************
* 本文件静态函数声明 ('static')
******************************************************************************/
static void vCAN_Receive_MCU_Message(strLISHUI_CAN *pCanMsg,strBikeInfo *pBikeInfo);
static void vCAN_Receive_BMS_Message(strLISHUI_CAN *pCanMsg,strBikeInfo *pBikeInfo);
static void vCan_Send_DisplayMessage(uint32_t PGN,strBikeInfo   *pBikeInfo);
static void vPROTOCOL_Factory_Response(uint32_t Cmd,uint16_t Data);
/******************************************************************************
* 全局变量定义
******************************************************************************/
strBikeInfo     gxBikeInfo = {0};         /*车辆数据*/
static uint32_t gulCommunicationCnt = 0;
/*****************************************************************************
* 函数实现 - global ('extern') and local ('static')
******************************************************************************/

/******************************************************************************
** 功  能：CAN协议初始化函数
** 参  数：无
** 返回值：无
** 备  注：用于初始化CAN协议模块的相关变量，同时创建收发队列。
******************************************************************************/
void vPROTOCOL_Init(void)
{
    muilt_cyc_fifo_error_code_t    lxState;
    MCF_ApplyFifo(gxCAN_RxQueue_Len,gxCAN_RxQueue,&lxState);     /*初始化接收队列*/
    MCF_ApplyFifo(gxCAN_TxQueue_Len,gxCAN_TxQueue,&lxState);     /*初始化发送队列*/
}

/******************************************************************************
** 功  能：CAN发送函数
** 参  数：pCanMessage-指向要发送的数据结构体
** 返回值：无
** 备  注：
******************************************************************************/
static void vCAN_Transmit(strLISHUI_CAN *pCanMessage)
{
    uint8_t n;
    can_tx_message_type    lxCanTxMessage;


    lxCanTxMessage.id_type      = CAN_ID_EXTENDED;      /*扩展帧*/
    lxCanTxMessage.frame_type   = CAN_TFT_DATA;         /*数据帧*/
    lxCanTxMessage.dlc          = 8;                    /*数据长度*/
    lxCanTxMessage.extended_id  = (pCanMessage->Priority << 26) | (pCanMessage->Reserver << 26) | (pCanMessage->Data_Page << 25)
                                  | (pCanMessage->PDU_Format << 16) | (pCanMessage->PS << 8) | pCanMessage->Source_Adress;

    for(n = 0; n < 8; n++)
    {
        lxCanTxMessage.data[n] = pCanMessage->Data[n];
    }

    /*调用发送函数进行发送*/
    can_message_transmit(CAN1,&lxCanTxMessage);
}

/******************************************************************************
** 功  能：将接收到的Can帧解析为溧水的Can数据结构
** 参  数：pCanMessage-接收到的Can数据结构体指针
** 返回值：无
** 备  注：该函数是整个Can协议模块的入口函数。当CAN总线接收一帧Can数据后，调用该函数，
**        将Can消息帧转换为溧水的CAN数据格式，并且放入接收队列
******************************************************************************/
void vCAN_CanMsgToLISHUIMsg(can_rx_message_type *pCanMessage)
{
    strLISHUI_CAN lxLISHUI_CanMessage;
    muilt_cyc_fifo_error_code_t lxState;
    unsigned char n;

    lxLISHUI_CanMessage.Source_Adress = pCanMessage->extended_id         & 0x000000FF;
    lxLISHUI_CanMessage.PS            = (pCanMessage->extended_id >> 8)  & 0x000000FF;
    lxLISHUI_CanMessage.PDU_Format    = (pCanMessage->extended_id >> 16) & 0x000000FF;
    lxLISHUI_CanMessage.Data_Page     = (pCanMessage->extended_id >> 24) & 0x00000001;
    lxLISHUI_CanMessage.Reserver      = (pCanMessage->extended_id >> 25) & 0x00000001;
    lxLISHUI_CanMessage.Priority      = (pCanMessage->extended_id >> 26) & 0x00000007;

    for(n = 0; n < pCanMessage->dlc; n++)
    {
        lxLISHUI_CanMessage.Data[n] = pCanMessage->data[n];
    }

    /*将转换后的Can数据放入FIFO队列*/
    MCF_WriteDataInFifo(gxCAN_RxQueue,(uint8_t *)&lxLISHUI_CanMessage,sizeof(strLISHUI_CAN),&lxState);
}




/******************************************************************************
** 功  能：CAN协议轮询，处理收发
** 参  数：无
** 返回值：无
** 备  注：该函数是模块主函数，应定时调用，调用周期一般10-20ms，定时处理收发
******************************************************************************/
void vPROTOCOL_Loop(void)
{
    static uint32_t lulTicks = 0;

    muilt_cyc_fifo_error_code_t lxState;
    uint16_t lxFifoCanReadLen;
    uint16_t lxActualReadLen;

    strLISHUI_CAN       lxLISHUI_CAN_RxMessage;
    strLISHUI_CAN       lxLISHUI_CAN_TxMessage;

    /*接收到控制开机信号后，100ms发送一次的帧*/
    if(lulTicks % (100 / CAN_LOOP_CYCLE) == 0)
    {
        vCan_Send_DisplayMessage(0x00FD01,&gxBikeInfo);
    }


    lulTicks++;
    gulCommunicationCnt++;

    /*10S之内，通信超时变量未复位，报30错误*/
    if(gulCommunicationCnt > (10000 / CAN_LOOP_CYCLE))
    {
        gxBikeInfo.ErrCode = 0x30;
        gxBikeInfo.MCU.Speed = 0;   /*报30错误时，强制把速度变为0*/
        gxBikeInfo.MCU.Current = 0; /*报30错误时，强制把电流变为0*/
    }
    else
    {
        if(gxBikeInfo.ErrCode == 0x30)
        {
            gxBikeInfo.ErrCode = 0;
        }
    }

    /*判断接收队列是否非空*/
    MCF_GetCanReadLen(gxCAN_RxQueue,&lxFifoCanReadLen,&lxState);
    if(lxState == kMultiCycFiFo_Error_NONE && lxFifoCanReadLen > 0)
    {
        MCF_ReadDataFromFifo(gxCAN_RxQueue,sizeof(strLISHUI_CAN),(uint8_t *)&lxLISHUI_CAN_RxMessage,&lxActualReadLen,&lxState);/*从队列中取出一组CAN数据*/
        if(lxActualReadLen == sizeof(strLISHUI_CAN) && lxState == kMultiCycFiFo_Error_NONE)
        {
            gulCommunicationCnt = 0;        /*复位通信超时计数*/
            /*判断目的节点*/
            switch(lxLISHUI_CAN_RxMessage.Source_Adress)
            {
            case ID_MCU:          /*控制器发送的消息*/
            {
                vCAN_Receive_MCU_Message(&lxLISHUI_CAN_RxMessage,&gxBikeInfo);
                break;
            }
            case ID_BMS_1:        /*主BMS发送的消息*/
            {
                vCAN_Receive_BMS_Message(&lxLISHUI_CAN_RxMessage,&gxBikeInfo);
                break;
            }

            default:
                break;              /*其它消息不接收*/
            }
        }
    }

    /*判断发送缓冲区是否有数据需要发送*/
    MCF_GetCanReadLen(gxCAN_TxQueue,&lxFifoCanReadLen,&lxState);
    if(lxState == kMultiCycFiFo_Error_NONE && lxFifoCanReadLen > 0)
    {
        MCF_ReadDataFromFifo(gxCAN_TxQueue,sizeof(strLISHUI_CAN),(uint8_t *)&lxLISHUI_CAN_TxMessage,&lxActualReadLen,&lxState);/*从队列中取出一组CAN数据*/
        if(lxActualReadLen == sizeof(strLISHUI_CAN) && lxState == kMultiCycFiFo_Error_NONE)
        {
            vCAN_Transmit(&lxLISHUI_CAN_TxMessage);                          /*将八方CAN数据转换为实际的CAN帧，并发送*/
        }
    }
}

/******************************************************************************
** 功  能：接收处理源节点为控制器的消息
** 参  数：pBFCanMsg-接收到的Can消息指针，pBikeInfo-车辆信息结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
static void vCAN_Receive_MCU_Message(strLISHUI_CAN *pCanMsg,strBikeInfo *pBikeInfo)
{

    uint32_t lulRequest_PGN;

    switch(pCanMsg->PS)
    {
    case 0x01:          /*PGN:0x00FE01,系统工作及匹配信息*/
    {
        pBikeInfo->MCU.Protocol_Ver     = (uint16_t)(pCanMsg->Data[1] << 8) | pCanMsg->Data[1];            /*通讯协议版本号*/
        pBikeInfo->MCU.Encryption_Type  = pCanMsg->Data[2];                  /*加密方式*/
        pBikeInfo->MCU.Key1             = pCanMsg->Data[3];                  /*密钥1*/
        pBikeInfo->MCU.Key2             = pCanMsg->Data[4];                  /*密钥2*/
        pBikeInfo->MCU.Key3             = pCanMsg->Data[5];                  /*密钥3*/
        pBikeInfo->MCU.Key4             = pCanMsg->Data[6];                  /*密钥4*/
        pBikeInfo->MCU.Key_Type         = pCanMsg->Data[7];                  /*按键连接方式*/
        break;
    }
    case 0x02:          /*PGN：0x00FE02，控制器数据1*/
    {


        pBikeInfo->MCU.Pas              = pCanMsg->Data[0]        & 0x0F;   /*档位*/
        pBikeInfo->MCU.Walk             = (pCanMsg->Data[0] >> 4) & 0x01;   /*助力推行状态*/
        pBikeInfo->MCU.Lamp             = (pCanMsg->Data[0] >> 5) & 0x01;   /*大灯状态*/
        pBikeInfo->MCU.Break            = (pCanMsg->Data[0] >> 6) & 0x01;   /*刹车状态*/
        pBikeInfo->MCU.Motor_Output     = (pCanMsg->Data[0] >> 7) & 0x01;   /*电机输出状态*/

        pBikeInfo->MCU.InSetting        = (pCanMsg->Data[1] >> 5) & 0x01;   /*仪表进设置状态标志*/
        pBikeInfo->MCU.Display_On       = (pCanMsg->Data[1] >> 4) & 0x01;   /*仪表是否显示*/

        pBikeInfo->MCU.Speed            = ((uint16_t)(pCanMsg->Data[1] & 0x0F) << 8) | pCanMsg->Data[2];        /*车速*/
        pBikeInfo->MCU.Rpm              = pCanMsg->Data[3];                 /*踏频*/
        pBikeInfo->MCU.Torque           = pCanMsg->Data[4];                 /*脚踏力矩*/
        pBikeInfo->MCU.ErrCode          = ((uint16_t)pCanMsg->Data[5] << 8) | pCanMsg->Data[6];                 /*故障码*/

        pBikeInfo->MCU.Button           = pCanMsg->Data[7];                 /*按键状态*/


        break;
    }
    case 0x03:          /*PGN：0x00FE03，控制器数据2*/
    {
        pBikeInfo->MCU.Voltage          = ((uint16_t)pCanMsg->Data[1] << 8) | pCanMsg->Data[0];     /*电压，0.1V*/
        pBikeInfo->MCU.Current          = ((int16_t)pCanMsg->Data[3] << 8) | pCanMsg->Data[2];      /*电流,0.1A*/

        pBikeInfo->MCU.MCU_Temp         = pCanMsg->Data[4];                 /*控制器温度*/
        pBikeInfo->MCU.Motor_Temp       = pCanMsg->Data[5];                 /*电机温度*/

        pBikeInfo->MCU.Power_Soc        = pCanMsg->Data[6];                 /*实时功率百分比*/
        pBikeInfo->MCU.Soc              = pCanMsg->Data[7];                 /*电量SOC*/

        /*防止上传的数据超量程*/
        if(pBikeInfo->MCU.Power_Soc > 100)  pBikeInfo->MCU.Power_Soc = 100;
        if(pBikeInfo->MCU.Soc > 100)        pBikeInfo->MCU.Soc       = 100;

        /*根据控制器上传的电压，判断是否欠压，发送对应的欠压标志*/
        if(pBikeInfo->MCU.Voltage < pBikeInfo->Display.Low_Voltage)
        {
            pBikeInfo->Display.Low_Voltage_Flag = 1;
        }
        else
        {
            pBikeInfo->Display.Low_Voltage_Flag = 0;
        }
        break;
    }
    case 0x04:          /*PGN:0x00FE04，控制器数据3*/
    {
        pBikeInfo->MCU.ODO              = ((uint32_t)pCanMsg->Data[2] << 16) | ((uint32_t)pCanMsg->Data[1] << 8) | pCanMsg->Data[0];    /*ODO*/
        pBikeInfo->MCU.ErrCode_Ext      = ((uint16_t)pCanMsg->Data[4] << 8) | pCanMsg->Data[3];             /*扩展错误代码*/
        break;
    }

    case 0x28:          /*此处0x28为仪表ID，表示目的地址是仪表的报文*/
    {
        if(pCanMsg->PDU_Format == 0xEA) /*PGN请求报文*/
        {
            lulRequest_PGN = ((uint32_t)pCanMsg->Data[2] << 16) | ((uint32_t)pCanMsg->Data[1] << 8) | ((uint32_t)pCanMsg->Data[0]);
            vCan_Send_DisplayMessage(lulRequest_PGN,&gxBikeInfo);       /*根据请求的PGN，发送对应消息*/
        }
    }
    default:
    {
        break;
    }
    }
}

/******************************************************************************
** 功  能：接收处理源节点为BMS的消息
** 参  数：pBFCanMsg-接收到的Can消息指针，pBikeInfo-车辆信息结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
static void vCAN_Receive_BMS_Message(strLISHUI_CAN *pCanMsg,strBikeInfo *pBikeInfo)
{
    uint8_t n;
    uint16_t lusTemp;
    switch(pCanMsg->PS)
    {
    case 0x25:      /*PGN：0x00FF25，BMS匹配信息*/
    {
        pBikeInfo->Battery.PowerOn          = (pCanMsg->Data[0] >> 7) & 0x01;       /*开机标志*/
        pBikeInfo->Battery.Encryption_Type  = pCanMsg->Data[0] & 0x7F;              /*加密方式*/
        pBikeInfo->Battery.Key              = pCanMsg->Data[1];                     /*密钥*/
        pBikeInfo->Battery.Device_Type      = ((uint16_t)pCanMsg->Data[3] << 8) | pCanMsg->Data[2]; /*产品类型*/
        pBikeInfo->Battery.User_SN          = ((uint16_t)pCanMsg->Data[5] << 8) | pCanMsg->Data[4]; /*客户编码*/
        pBikeInfo->Battery.Vehicle_Type     = ((uint16_t)pCanMsg->Data[7] << 8) | pCanMsg->Data[6]; /*车辆型号*/
        break;
    }
    case 0x01:      /*PGN：0x00FF01，电池组温度*/
    {
        pBikeInfo->Battery.Temp_Num         = pCanMsg->Data[0];                     /*温度探头数量*/
        for(n = 0; n < pBikeInfo->Battery.Temp_Num; n++)
        {
            pBikeInfo->Battery.Temp[n] = pCanMsg->Data[n];                          /*各探头温度*/
        }
        break;
    }
    case 0x02:      /*PGN：0x00FF02，电池组综合数据*/
    {
        pBikeInfo->Battery.SOH              = pCanMsg->Data[0];
        pBikeInfo->Battery.SOC              = pCanMsg->Data[1];
        pBikeInfo->Battery.Capacity_Remain  = ((uint16_t)pCanMsg->Data[3] << 8) | pCanMsg->Data[2]; /*剩余容量*/
        pBikeInfo->Battery.Capacity_Full    = ((uint16_t)pCanMsg->Data[5] << 8) | pCanMsg->Data[4]; /*剩余容量*/
        pBikeInfo->Battery.Capacity_Design  = ((uint16_t)pCanMsg->Data[7] << 8) | pCanMsg->Data[6]; /*剩余容量*/
        break;
    }
    case 0x03:      /*PGN：0x00FF03，电芯电压1*/
    {
        pBikeInfo->Battery.Cell_Num_Serial   = pCanMsg->Data[0];                     /*电池组串数*/
        pBikeInfo->Battery.Cell_Num_Parallel = pCanMsg->Data[1];                     /*电池组并数*/
        for(n = 0; n < 3; n++)
        {
            pBikeInfo->Battery.Cell_Volt[n] = ((uint16_t)pCanMsg->Data[3 + 2 * n] << 8) | pCanMsg->Data[2 + 2 * n]; /*电芯1-3电压*/
        }
        break;
    }
    case 0x04:      /*PGN：0x00FF04，电芯电压2*/
    {
        for(n = 0; n < 4; n++)
        {
            pBikeInfo->Battery.Cell_Volt[3 + n] = ((uint16_t)pCanMsg->Data[1 + 2 * n] << 8) | pCanMsg->Data[2 * n]; /*电芯4-7*/
        }
        break;
    }
    case 0x05:      /*PGN：0x00FF05，电芯电压3*/
    {
        for(n = 0; n < 4; n++)
        {
            pBikeInfo->Battery.Cell_Volt[7 + n] = ((uint16_t)pCanMsg->Data[1 + 2 * n] << 8) | pCanMsg->Data[2 * n]; /*电芯8-11*/
        }
        break;
    }
    case 0x06:      /*PGN：0x00FF06，电芯电压4*/
    {
        for(n = 0; n < 4; n++)
        {
            pBikeInfo->Battery.Cell_Volt[11 + n] = ((uint16_t)pCanMsg->Data[1 + 2 * n] << 8) | pCanMsg->Data[2 * n]; /*电芯12-15*/
        }
        break;
    }
    case 0x0A:      /*PGN：0x00FF0A，电池组实时电压电流*/
    {
        pBikeInfo->Battery.Voltage          = ((uint16_t)pCanMsg->Data[1] << 8) | pCanMsg->Data[0];     /*电池组电压*/
        pBikeInfo->Battery.Current          = ((uint16_t)pCanMsg->Data[3] << 8) | pCanMsg->Data[2];     /*电池组电流*/
        pBikeInfo->Battery.MaxCurrent_Continued = pCanMsg->Data[4];                                     /*最大允许持续电流*/
        pBikeInfo->Battery.MaxCurrent_Peak      = pCanMsg->Data[5];                                     /*最大允许峰值电流*/
        pBikeInfo->Battery.MaxCurrent_Charge    = pCanMsg->Data[6];                                     /*最大允许充电电流*/
        pBikeInfo->Battery.Power_Scale          = pCanMsg->Data[7];                                     /*系统功率输入系数*/
        break;
    }
    case 0x0B:      /*PGN：0x00FF0B，电池组警告和保护*/
    {
        pBikeInfo->Battery.AlarmInfo        = ((uint32_t)pCanMsg->Data[3] << 24) | ((uint32_t)pCanMsg->Data[2] << 16) | ((uint32_t)pCanMsg->Data[1] << 8) | pCanMsg->Data[0];/*警告信息*/
        pBikeInfo->Battery.ProtectInfo      = ((uint32_t)pCanMsg->Data[7] << 24) | ((uint32_t)pCanMsg->Data[6] << 16) | ((uint32_t)pCanMsg->Data[5] << 8) | pCanMsg->Data[4];/*警告信息*/
        break;
    }
    case 0x0C:      /*PGN：0x00FF0C，电池组状态*/
    {
        pBikeInfo->Battery.Charge_State     = pCanMsg->Data[0];         /*充电状态*/
        pBikeInfo->Battery.Discharge_State  = pCanMsg->Data[1];         /*放电状态*/

        break;
    }
    case 0x10:      /*PGN：0x00FF10，电池组记录数据*/
    {
        pBikeInfo->Battery.Cycle_Times                = ((uint16_t)pCanMsg->Data[1] << 8) | pCanMsg->Data[0];   /*循环次数*/
        pBikeInfo->Battery.Charging_Time_Interval     = ((uint16_t)pCanMsg->Data[3] << 8) | pCanMsg->Data[2];   /*充电时间间隔*/
        pBikeInfo->Battery.Charging_Time_Interval_Max = ((uint16_t)pCanMsg->Data[5] << 8) | pCanMsg->Data[4];   /*最大充电时间间隔*/
        pBikeInfo->Battery.Active_Time                = ((uint16_t)pCanMsg->Data[7] << 8) | pCanMsg->Data[6];   /*激活时间*/
        break;
    }

    case 0x15:      /*PGN：0x00FF15，电池组条码*/
    {
        pBikeInfo->Battery.ID_Num       = pCanMsg->Data[0];     /*条码长度*/
        for(n = 0; n < 7; n++)
        {
            pBikeInfo->Battery.ID[n] = pCanMsg->Data[1 + n];    /*条码*/
        }
        break;
    }
    case 0x16:      /*PGN，0x00FF16，电池组条码2*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->Battery.ID[7 + n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x17:      /*PGN，0x00FF17，电池组条码3*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->Battery.ID[15 + n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x18:      /*PGN，0x00FF18，电池组条码4*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->Battery.ID[23 + n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x20:      /*PGN，0x00FF20，电池软件版本号1*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->Battery.Soft_Version_1[n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x21:      /*PGN，0x00FF21，电池硬件版本号1*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->Battery.Hard_Version_1[n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x22:      /*PGN，0x00FF22，电池硬件版本号2*/
    {
        for(n = 0; n < 8; n++)
        {
            pBikeInfo->Battery.Hard_Version_2[n] = pCanMsg->Data[n];
        }
        break;
    }
    case 0x24:      /*PGN，0x00FF24，电池RTC*/
    {
        lusTemp = ((uint16_t)pCanMsg->Data[1] << 8) | pCanMsg->Data[0];
        pBikeInfo->Battery.RTC_Time.Year     = (lusTemp >> 9);               /*年*/
        pBikeInfo->Battery.RTC_Time.Month    = (lusTemp >> 5) & 0x0F;        /*月*/
        pBikeInfo->Battery.RTC_Time.Day      = lusTemp & 0x1F;               /*日*/
        pBikeInfo->Battery.RTC_Time.Hour     = pCanMsg->Data[2];             /*小时*/
        pBikeInfo->Battery.RTC_Time.Min      = pCanMsg->Data[3];             /*分钟*/
        pBikeInfo->Battery.RTC_Time.Sec      = pCanMsg->Data[4];             /*秒*/
        lusTemp = ((uint16_t)pCanMsg->Data[6] << 8) | pCanMsg->Data[5]; /*上次校准时间*/
        pBikeInfo->Battery.RTC_LastCalibration.Year  = (lusTemp >> 9);
        pBikeInfo->Battery.RTC_LastCalibration.Month = (lusTemp >> 5) & 0x0F;
        pBikeInfo->Battery.RTC_LastCalibration.Day   = lusTemp & 0x1F;
        break;
    }
    }
}

/******************************************************************************
** 功  能：仪表发送消息
** 参  数：PGN-要发送的PGN号，pBikeInfo-车辆信息结构体指针
** 返回值：无
** 备  注：
******************************************************************************/
static void vCan_Send_DisplayMessage(uint32_t PGN,strBikeInfo   *pBikeInfo)
{
    strLISHUI_CAN   lxCanTxMsg;
    muilt_cyc_fifo_error_code_t lxState;


    switch(PGN)
    {
    case 0x00FD01:/*仪表匹配消息*/
    {
        lxCanTxMsg.Priority      = 0x03;        /*0x00FD01的PGN，采用优先级3发送*/
        lxCanTxMsg.Data[0] = (pBikeInfo->Display.Low_Voltage_Flag << 6) | (pBikeInfo->Display.Lamp << 5) | (pBikeInfo->Display.Walk << 4) | pBikeInfo->Display.Pas;
        lxCanTxMsg.Data[1] = 0;
        lxCanTxMsg.Data[2] = 0;
        lxCanTxMsg.Data[3] = 0;
        lxCanTxMsg.Data[4] = 0;
        lxCanTxMsg.Data[5] = 0;
        lxCanTxMsg.Data[6] = 0;
        lxCanTxMsg.Data[7] = 0;
        break;
    }
    default:/*其它用到*/
    {
        lxCanTxMsg.Priority      = 0x06;        /*其它的PGN，采用优先级6发送*/
        lxCanTxMsg.Data[0] = 0;
        lxCanTxMsg.Data[1] = 0;
        lxCanTxMsg.Data[2] = 0;
        lxCanTxMsg.Data[3] = 0;
        lxCanTxMsg.Data[4] = 0;
        lxCanTxMsg.Data[5] = 0;
        lxCanTxMsg.Data[6] = 0;
        lxCanTxMsg.Data[7] = 0;
        break;
    }

    }

    lxCanTxMsg.Data_Page     = 0x00;
    lxCanTxMsg.Reserver      = 0x00;
    lxCanTxMsg.PDU_Format    = (PGN >> 8) & 0x000000FF;
    lxCanTxMsg.PS            = (PGN & 0x000000FF);
    lxCanTxMsg.Source_Adress = (uint8_t)ID_DP;

    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxCanTxMsg,sizeof(strLISHUI_CAN),&lxState); /*将数据放入发送队列，排队发送*/
}

/******************************************************************************
** 功  能：仪表向节点发送PGN请求
** 参  数：Dst_ID-目的节点地址，PGN-要请求的PGN号
** 返回值：无
** 备  注：
******************************************************************************/
void vCan_Send_RequestPGN(enuDEVICE_ID Dst_ID,uint32_t PGN)
{
    strLISHUI_CAN   lxCanTxMsg;
    muilt_cyc_fifo_error_code_t lxState;

    lxCanTxMsg.Priority      = 6;
    lxCanTxMsg.Reserver      = 0;
    lxCanTxMsg.Data_Page     = 0;
    lxCanTxMsg.PDU_Format    = 0xEA;            /*请求PGN专用PF*/
    lxCanTxMsg.PS            = (uint8_t)Dst_ID;
    lxCanTxMsg.Source_Adress = (uint8_t)ID_DP;  /*源地址是仪表*/
    lxCanTxMsg.Data[0]       = PGN;
    lxCanTxMsg.Data[1]       = PGN >> 8;
    lxCanTxMsg.Data[2]       = PGN >> 16;
    lxCanTxMsg.Data[3]       = 0x00;
    lxCanTxMsg.Data[4]       = 0x00;
    lxCanTxMsg.Data[5]       = 0x00;
    lxCanTxMsg.Data[6]       = 0x00;
    lxCanTxMsg.Data[7]       = 0x00;
    MCF_WriteDataInFifo(gxCAN_TxQueue,(uint8_t *)&lxCanTxMsg,sizeof(strLISHUI_CAN),&lxState); /*将数据放入发送队列，排队发送*/
}






/******************************************************************************
** 功  能：设置大灯状态
** 参  数：State-大灯状态。0-关闭，1-打开
** 返回值：无
** 备  注：所有协议通用
******************************************************************************/
void vPROTOCOL_Set_Lamp(uint8_t State)
{
    gxBikeInfo.Display.Lamp = State;/*大灯状态*/
}

/******************************************************************************
** 功  能：设置档位范围
** 参  数：Pas_Range
** 返回值：无
** 备  注：溧水控制器，不支持设置挡位范围，暂时保留
**
******************************************************************************/
void vPROTOCOL_Set_Pas_Range(int8_t Pas_Range)
{

}

/******************************************************************************
** 功  能：设置欠压值
** 参  数：LowVoltage-欠压值，0.1V
** 返回值：无
** 备  注：
**
******************************************************************************/
void vPROTOCOL_Set_Low_Voltage(uint16_t LowVoltage)
{
    gxBikeInfo.Display.Low_Voltage = LowVoltage;
}

/******************************************************************************
** 功  能：设置档位
** 参  数：Pas-档位值，最大为9，最小为-1,-1表示助推档
** 返回值：无
** 备  注：本函数在仪表为主机的模式下可用，在TUV模式下，仪表发送的档位是转发控制器的数据
**         不要调用该函数
**         安乃达控制器，默认支持5个挡位，当选择3档位时，发送1、3、5档
**         特殊7档和9档的，需要更改控制器程序，暂不考虑
******************************************************************************/
void vPROTOCOL_Set_Pas(int8_t Pas)
{
    /*此处对于安乃达协议的助推尚有疑问，是否这样处理，需要控制器验证*/
    if(Pas > -1)
    {
        gxBikeInfo.Display.Walk    = 0;         /*禁止推行*/
        gxBikeInfo.Display.Pas     = Pas;       /*按照实际挡位发送*/

    }
    else
    {
        gxBikeInfo.Display.Walk    = 1;  /*推行使能*/
    }
}

/******************************************************************************
** 功  能：设置助推允许
** 参  数：En-0,禁止助推，1-允许助推
** 返回值：无
** 备  注：本函数为TUV模式下调用的函数，告诉控制器进助推预触发。
******************************************************************************/
void vPROTOCOL_Set_Push_En(uint8_t En)
{

}



/******************************************************************************
** 功  能：设置发送一次配置数据
** 参  数：无
** 返回值：无
** 备  注：本函数运行后，只发送一次配置数据。然后会转为发送运行数据
**         所有协议通用
******************************************************************************/
void vPROTOCOL_Send_Config_Data_OneTime(void)
{

}

/******************************************************************************
** 功  能：停止发送数据
** 参  数：无
** 返回值：无
** 备  注：本函数运行后，即停止发送数据。直到再次设置发送配置数据或发送运行数据
**         所有协议通用
******************************************************************************/
void vPROTOCOL_Send_Stop(void)
{

}

/******************************************************************************
** 功  能：获取控制器上传的电压
** 参  数：无
** 返回值：电压，0.1V
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_Voltage(void)
{
    return gxBikeInfo.MCU.Voltage;
}

/******************************************************************************
** 功  能：获取当前电流值
** 参  数：无
** 返回值：实际电流值的10倍。比如实际电流12.3A，返回123
** 备  注：所有协议通用
******************************************************************************/
uint16_t usPROTOCOL_Get_Current(void)
{
    return gxBikeInfo.MCU.Current;
}

/******************************************************************************
** 功  能：获取电池容量
** 参  数：无
** 返回值：-1表示未获取到电池容量，电池容量，0-100%
** 备  注：
******************************************************************************/
int8_t cPROTOCOL_Get_Soc(void)
{
    return gxBikeInfo.MCU.Soc;/*没有读取到BMS的SOC，但是读取到了控制器的SOC，返回控制器的SOC*/
}


/******************************************************************************
** 功  能：获取当前车速
** 参  数：无
** 返回值：实际车速*10.比如返回120，实际车速即12.0Km/h
** 备  注：所有协议通用
******************************************************************************/
uint16_t usPROTOCOL_Get_Speed(void)
{
    return gxBikeInfo.MCU.Speed;
}

/******************************************************************************
** 功  能：获取错误代码
** 参  数：无
** 返回值：十六进制的错误代码
** 备  注：包括30错误代码（通信超时）
**         所有协议通用
******************************************************************************/
uint8_t ucPROTOCOL_Get_Errcode(void)
{
    uint8_t n;
    uint8_t ErrCodeTab[] = {0x10,0x11,0x21,0x12,0x24,0x23,0x22,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x25};

    if(gxBikeInfo.ErrCode > 0)
    {
        return gxBikeInfo.ErrCode;      /*30通信故障*/
    }
    else
    {
        for(n = 0; n < 16; n++)
        {
            if((gxBikeInfo.MCU.ErrCode & ((uint16_t)0x0001 << n)) != 0)
            {
                return ErrCodeTab[n];
            }
        }
        return 0;   /*遍历一遍，没有故障码，返回0*/
    }

}





/******************************************************************************
** 功  能：获取ODO里程
** 参  数：无
** 返回值：ODO值，0.1Km
** 备  注：
******************************************************************************/
uint32_t ulPROTOCOL_Get_Odo(void)
{
    return gxBikeInfo.MCU.ODO;
}



/******************************************************************************
** 功  能：获取助推状态
** 参  数：无
** 返回值：助推状态。0-未启动，1-准备就绪，2-助推中
** 备  注：该函数在TUV模式时用
******************************************************************************/
uint8_t ucPROTOCOL_Get_Push_Status(void)
{
    return gxBikeInfo.MCU.Walk;
}

/******************************************************************************
** 功  能：获取档位
** 参  数：无
** 返回值：档位数值，0-15
** 备  注：该函数在TUV模式时，用于获取控制器发送的档位
******************************************************************************/
uint8_t ucPROTOCOL_Get_Pas(void)
{
    return gxBikeInfo.MCU.Pas;
}

/******************************************************************************
** 功  能：获取是否进入设置
** 参  数：无
** 返回值：0-未进入设置，1-进入设置
** 备  注：该函数在TUV模式时使用，用于判断是否进入设置
******************************************************************************/
uint8_t ucPROTOCOL_Get_IsInSetting(void)
{
    return gxBikeInfo.MCU.InSetting;
}

/******************************************************************************
** 功  能：获取前大灯状态
** 参  数：无
** 返回值：0-未开灯，1-开灯
** 备  注：该函数在TUV模式时使用
******************************************************************************/
uint8_t ucPROTOCOL_Get_Lamp_Status(void)
{
    return gxBikeInfo.MCU.Lamp;
}



/******************************************************************************
** 功  能：获取控制器发送过来的上键状态
** 参  数：无
** 返回值：0-未按下，1-按下
** 备  注：该函数在TUV模式时使用
******************************************************************************/
uint8_t ucPROTOCOL_Get_Up_Key(void)
{
    return (gxBikeInfo.MCU.Button >> 3) & 0x01;
}

/******************************************************************************
** 功  能：获取控制器发送过来的下键状态
** 参  数：无
** 返回值：0-未按下，1-按下
** 备  注：该函数在TUV模式时使用
******************************************************************************/
uint8_t ucPROTOCOL_Get_Down_Key(void)
{
    return (gxBikeInfo.MCU.Button >> 2) & 0x01;
}

/******************************************************************************
** 功  能：获取控制器发送过来的电源键状态
** 参  数：无
** 返回值：0-未按下，1-按下
** 备  注：该函数在TUV模式时使用
******************************************************************************/
uint8_t ucPROTOCOL_Get_Power_Key(void)
{
    return (gxBikeInfo.MCU.Button >> 1) & 0x01;
}

/******************************************************************************
** 功  能：获取控制器发送过来的推行键状态
** 参  数：无
** 返回值：0-未按下，1-按下
** 备  注：该函数在TUV模式时使用
******************************************************************************/
uint8_t ucPROTOCOL_Get_Push_Key(void)
{
    return gxBikeInfo.MCU.Button & 0x01;
}



/******************************************************************************
** 功  能：获取BMS电压
** 参  数：无
** 返回值：BMS电压值，0.1V
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_BMS_Voltage(void)
{
    return gxBikeInfo.Battery.Voltage;
}

/******************************************************************************
** 功  能：获取BMS电流
** 参  数：无
** 返回值：BMS电流值，0.1V
** 备  注：
******************************************************************************/
int16_t sPROTOCOL_Get_BMS_Current(void)
{
    return (int32_t)gxBikeInfo.Battery.Current - 32768;
}

/******************************************************************************
** 功  能：获取BMS的SOH
** 参  数：无
** 返回值：SOH，1%精度
** 备  注：
******************************************************************************/
uint8_t ucPROTOCOL_Get_BMS_SOH(void)
{
    return gxBikeInfo.Battery.SOH;
}

/******************************************************************************
** 功  能：获取BMS的SOC
** 参  数：无
** 返回值：SOC，1%精度
** 备  注：
******************************************************************************/
int8_t cPROTOCOL_Get_BMS_SOC(void)
{
    return gxBikeInfo.Battery.SOC;
}

/******************************************************************************
** 功  能：获取BMS的剩余容量
** 参  数：无
** 返回值：剩余容量值，0.01Ah
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_BMS_ResCap(void)
{
    return gxBikeInfo.Battery.Capacity_Remain;
}

/******************************************************************************
** 功  能：获取BMS的循环次数
** 参  数：无
** 返回值：循环次数
** 备  注：
******************************************************************************/
uint8_t ucPROTOCOL_Get_BMS_CycleTimes(void)
{
    return gxBikeInfo.Battery.Cycle_Times;
}

/******************************************************************************
** 功  能：获取电池组串数
** 参  数：无
** 返回值：电池组串联数量
** 备  注：
******************************************************************************/
uint8_t ucPROTOCOL_Get_BMS_SeriesNum(void)
{
    return gxBikeInfo.Battery.Cell_Num_Serial;
}

/******************************************************************************
** 功  能：获取电池组并数
** 参  数：无
** 返回值：电池组并联数量
** 备  注：
******************************************************************************/
uint8_t ucPROTOCOL_Get_BMS_ParallelNum(void)
{
    return gxBikeInfo.Battery.Cell_Num_Parallel;
}


/******************************************************************************
** 功  能：获取对应电芯的电压值
** 参  数：CellNum-电芯序号，从1开始，0-14
** 返回值：电芯电压，mv
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_BMS_Cell_Voltage(uint8_t CellNum)
{
    if(CellNum > 14)
    {
        CellNum = 14;
    }
    return gxBikeInfo.Battery.Cell_Volt[CellNum];
}

/******************************************************************************
** 功  能：获取BMS条码号
** 参  数：无
** 返回值：指向BMS条码号的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_BMS_Barcode(void)
{
    return (char *)&gxBikeInfo.Battery.ID;
}

/******************************************************************************
** 功  能：获取BMS软件版本号
** 参  数：无
** 返回值：指向BMS软件版本号的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_BMS_Soft_Version(void)
{
    return (char *)&gxBikeInfo.Battery.Soft_Version_1;
}

/******************************************************************************
** 功  能：获取BMS硬件版本号1
** 参  数：无
** 返回值：指向BMS硬件版本号1的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_BMS_Hard_Version_1(void)
{
    return (char *)&gxBikeInfo.Battery.Hard_Version_1;
}

/******************************************************************************
** 功  能：获取BMS硬件版本号2
** 参  数：无
** 返回值：指向BMS硬件版本号2的指针
** 备  注：
******************************************************************************/
char * pPROTOCOL_Get_BMS_Hard_Version_2(void)
{
    return (char *)&gxBikeInfo.Battery.Hard_Version_2;
}

/******************************************************************************
** 功  能：工厂指令的解析
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Factory_Command(can_rx_message_type *pCanRxMsg)
{
    uint16_t lusResponse;

    switch(pCanRxMsg->extended_id)
    {
    case 0x1F18016E:/*校准光感，返回0x03F8016E*/
    {
        lusResponse = vPhotoDiode_Calibration();
        vPROTOCOL_Factory_Response(pCanRxMsg->extended_id,lusResponse);
        break;
    }
    case 0x1F18025D:/*校准电压，返回0x03F8025D*/
    {
        lusResponse = vVoltage_Calibration();
        vPROTOCOL_Factory_Response(pCanRxMsg->extended_id,lusResponse);
        break;
    }
    case 0x1F180371:/*校准时间，返回0x03F80371*/
    {
        vDateTime_Calibration(pCanRxMsg->data[3],pCanRxMsg->data[4],pCanRxMsg->data[5],pCanRxMsg->data[0],pCanRxMsg->data[1],pCanRxMsg->data[2]);
        lusResponse = 1234;
        vPROTOCOL_Factory_Response(pCanRxMsg->extended_id,lusResponse);
        break;
    }
    case 0x1F18048E:/*清ODO，返回0x03F8048E*/
    {
        vClear_ODO();
        lusResponse = 5678;
        vPROTOCOL_Factory_Response(pCanRxMsg->extended_id,lusResponse);
        break;
    }
    }
}

/******************************************************************************
** 功  能：工厂指令的返回
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
static void vPROTOCOL_Factory_Response(uint32_t Cmd,uint16_t Data)
{
    can_tx_message_type    lxCanTxMessage;

    lxCanTxMessage.id_type      = CAN_ID_EXTENDED;      /*扩展帧*/
    lxCanTxMessage.frame_type   = CAN_TFT_DATA;         /*数据帧*/
    lxCanTxMessage.dlc          = 2;                    /*数据长度*/
    lxCanTxMessage.extended_id  = 0x03F80000 | (Cmd & 0x0000FFFF);
    lxCanTxMessage.data[0]      = Data >> 8;
    lxCanTxMessage.data[1]      = (uint8_t)Data;

    /*调用发送函数进行发送*/
    can_message_transmit(CAN1,&lxCanTxMessage);
}

/******************************************************************************
** 功  能：复位通信超时计数变量
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_ResetCommunicationOverTime(void)
{
    gulCommunicationCnt = 0;        /*复位通信超时计数*/
    if(gxBikeInfo.ErrCode == 0x30)
    {
        gxBikeInfo.ErrCode = 0;
    }
}


/******************************************************************************
** 功  能：开机上电时，设置默认要发送给控制器的数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Value_When_PowerOn(void)
{
    /*根据不同的电压，设定欠压值*/
    if(gtParam.Volt == 36)
    {
        vPROTOCOL_Set_Low_Voltage(gtParam.V_36_Tab[0]);
    }
    else if(gtParam.Volt == 48)
    {
        vPROTOCOL_Set_Low_Voltage(gtParam.V_48_Tab[0]);
    }
    else if(gtParam.Volt == 52)
    {
        vPROTOCOL_Set_Low_Voltage(gtParam.V_52_Tab[0]);
    }
    vPROTOCOL_Set_Pas_Range(gtParam.Pas_Max);
    vPROTOCOL_Set_Pas(0);                                           /*开机LOGO界面发0档*/
    //vPROTOCOL_Set_Speed_Limit(gtParam.Speed_Limit);                 /*限速*/
}

/******************************************************************************
** 功  能：退出设置时，设置默认要发送给控制器的数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Value_When_ExitSetting(void)
{
    //vPROTOCOL_Set_Wheel(usGet_Wheel_Size(gtParam.Wheel_Diameter));  /*轮径，为和其他协议兼容，轮径是×10以后的值*/
    //vPROTOCOL_Set_Speed_Limit(gtParam.Speed_Limit);                 /*限速*/
    /*根据不同的电压，设定欠压值*/
    if(gtParam.Volt == 36)
    {
        vPROTOCOL_Set_Low_Voltage(gtParam.V_36_Tab[0]);
    }
    else if(gtParam.Volt == 48)
    {
        vPROTOCOL_Set_Low_Voltage(gtParam.V_48_Tab[0]);
    }
    else if(gtParam.Volt == 52)
    {
        vPROTOCOL_Set_Low_Voltage(gtParam.V_52_Tab[0]);
    }

}


